/******************************************************************************
*
* This file is part of FreeTrack (http://code.google.com/p/qtfreetrack).
* BY Willy Gardiol (willy@gardiol.org)
*
* FreeTrack is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FreeTrack is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Foobar.  If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************/

#include "ftlist.h"

#define FTL_SHAKY_THREESHOLD 20

#define FTL_BACKGROUND_BRUSH QBrush( QColor( 64,64,64 ) )
#define FTL_SELECTED_BRUSH QBrush( QColor("gray") )

#define FTL_BACKGROUND_PEN QPen( QBrush(QColor("gray")), 0, Qt::DashDotLine )
#define FTL_SELECTED_PEN QPen( QBrush(QColor("white")), 2, Qt::DashLine )

FTList::FTList(QWidget *parent) :
    QWidget(parent)
{
    scrolling = false;
    // This widget will always expand to all the available space
    setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );
    scroll_start = scroll_offset = 0;
    row_height = 0;
    row_selected = -1;
}

void FTList::mousePressEvent(QMouseEvent * event)
{
    if ( !scrolling )
    {
        // We select the row on mouse press..
        row_selected = (event->y() - scroll_offset)/row_height;
        scroll_start = event->globalY();
        update();
    }
}

void FTList::mouseMoveEvent(QMouseEvent * event )
{
    if ( !scrolling )
    {
        // Calculate distance between this new point and the threeshold starting point
        int shaky_distance = abs(event->globalY() - scroll_start);
        // do the state change if the finger moved more than our threeshold
        scrolling = shaky_distance > FTL_SHAKY_THREESHOLD;
    }
    else
    {
        scroll_offset += event->globalY() - scroll_start;
        scroll_start = event->globalY();
        update();
    }
}

void FTList::mouseReleaseEvent(QMouseEvent * event)
{
    if ( !scrolling && (row_selected > -1) && (row_selected < strings.count()) )
            emit selected( strings.at( row_selected ) );
    else
        row_selected = -1;
    scrolling = false;
    update();
}

void FTList::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    int widget_width = width()-4;
    int widget_height = height()-4;
    int num_strings = strings.count();

    // Calculate row_height...
    row_height = (fontMetrics().size(Qt::TextSingleLine, "I").height()*3)/2;

    // Calculate overall height
    int total_height = num_strings*row_height;
    int delta = widget_height - total_height;

    // We have two cases:
    // 1) total_height < height
    if ( total_height <=  widget_height)
    {
        if ( scroll_offset < 0 )
            scroll_offset = 0;
        if ( scroll_offset > delta )
            scroll_offset = delta;
    }
    else
    {
        // 2) total_height > height
        if ( scroll_offset > 0 )
            scroll_offset = 0;
        if ( scroll_offset < delta )
            scroll_offset = delta;
    }

    int start_i = qMax( -scroll_offset/row_height, 0 );
    int last_i = qMin( strings.count(), widget_height/row_height + start_i+2);

    // Define the row rectangle
    QRect row_rect = QRect( 3, scroll_offset+start_i*row_height, widget_width-3, row_height );
    QPen old_pen = painter.pen();

    for ( int i = start_i; i < last_i; i++ )
    {
        // Paint the background...
        // Add a nice "border" effect...
        if (i == row_selected)
        {
            painter.fillRect( row_rect, FTL_SELECTED_BRUSH  );
            painter.setPen( FTL_SELECTED_PEN );
            painter.drawRect( row_rect );
        }
        else
        {
            painter.fillRect( row_rect, FTL_BACKGROUND_BRUSH );
            painter.setPen( FTL_BACKGROUND_PEN );
            painter.drawRect( row_rect );
        }
        painter.setPen( old_pen );
        // Draw the string...
        painter.drawText( row_rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, strings.at(i) );
        row_rect.translate(0, row_height);
    }

    painter.setPen( old_pen );
    // Draw a border to the widget
    painter.drawRect( rect().adjusted(1,1,-2,-2) );

    if ( total_height > widget_height )
    {
        int prop_h = total_height/widget_height;
        int bar_height = widget_height / prop_h - 14;
        int bar_start = abs(scroll_offset) / prop_h + 5;
        painter.setBrush( QBrush( Qt::Dense4Pattern ) );
        painter.drawRect( widget_width - 7, bar_start, 5, bar_height );
    }
}

void FTList::clear()
{
    strings.clear();
    scroll_offset = 0;
    row_selected = -1;
    scrolling = false;
    update();
}

void FTList::populate(const QStringList & sl )
{
    strings = sl;
    scroll_offset = 0;
    row_selected = -1;
    scrolling = false;
    update();
}

void FTList::append(const QStringList & sl )
{
    strings.append( sl );
    update();
}

void FTList::append(const QString & s )
{
    strings.append( s );
    update();
}
